import { resolveComponent, inject, computed } from 'vue';
import { formContextKey } from 'element-plus'
import mydate from './mydate.js';
import Server from './Server.js'

class Utils {
    getPValue(element, key) {
        var form = (key in element) ? element[key] : null;
        var p = element.$parent;
        while (!form && p) {
            form = (key in p) ? p[key] : null;
            p = p.$parent;
        }
        return form;
    }

    parseStringUI(obj, str1) {
        return str1.replaceAll(/\$(\w+)/g, (_, key) => {
            let el = obj[key];
            return this.parseStringUI(obj, el);
        })
    }

    parseUI2Template(ui) {
        if (!ui) return "";
        if (typeof (ui) == "string") return ui;
        if (typeof (ui) != "object") throw "ui必须是string或object类型";
        if (!ui.tpl) return "";
        let str1 = String(ui.tpl);
        return str1.replaceAll(/\$(\w+)/g, (_, key) => {
            let el = ui[key];
            if (!el) return "";
            if (typeof (el) == "string") {
                return this.parseStringUI(ui, el);
            }
            return this.parseUI2Template(el);
        })
    }



    getForm(element) {
        const form = inject(formContextKey, void 0);
        console.log("Utils.getForm", element, form);
        return form;
    }

    getFormData(element) {
        var formData = this.getPValue(element, "formData");
        if (!formData) {
            var frm = this.getForm(element);
            if (frm) {
                formData = frm["model"];
            }
        }
        return formData;
    }

    async getFormDefault(tbname, psearch) {
        psearch = psearch || {};
        return Server.getDM(tbname).then(tb => {
            let formData = { ID: 0 };
            for (var ix = 0; ix < tb.columns.length; ix++) {
                var col = tb.columns[ix];
                if (col.default != undefined) {
                    formData[col.code] = mydate.getDefaultValue(col.default, psearch);
                } else {
                    if (col.type == "int" || col.type == "number") {
                        if (col.control == "select" || col.control == "selectinput" || col.control == "combo") {
                            if (col.options && col.options.length > 0) {
                                formData[col.code] = col.options[0].value;
                            } else {
                                formData[col.code] = null;
                            }
                        } else {
                            formData[col.code] = 0;
                        }

                    } else if (col.type == "string") {
                        formData[col.code] = "";
                    } else if (col.type == "array") {
                        formData[col.code] = [];
                    }
                }
                let psval = psearch[col.code];
                if (psval != undefined) {
                    formData[col.code] = psval;
                }
            }
            return formData;
        });
    }
    async parseOptions(options, splitTag) {
        if (options) {
            if (typeof (options) == "string") {
                //label中的:使用::替换
                options = options.replaceAll("::", "◲◲◲◲");
                let hasIndex = options.indexOf(":") > 0;
                let index = 0;
                options = options.split(splitTag || ";").map(p => {
                    if (hasIndex) {
                        let ix = p.indexOf(":");
                        if (ix > 0) {
                            let index0 = parseInt(p.substring(0, ix));
                            if (!Number.isNaN(index0)) {
                                index = index0;
                                return { value: index++, label: p.substring(ix + 1) };
                            } else {
                                index++;
                                return { value: p.substring(0, ix), label: p.substring(ix + 1) };
                            }
                        }
                        return { value: index++, label: p.substring(ix + 1) };
                    }
                    return { value: p, label: p };
                }).map(x => {
                    if (typeof (x.value) == "string") {
                        x.value = x.value.replaceAll("◲◲◲◲", ":");
                    }
                    x.label = x.label.replaceAll("◲◲◲◲", ":");
                    return x;
                });
            } else if (options.url && typeof (options.url) == "string") {
                //动态加载options
                if (options.url.endsWith(".json")) {
                    return await Server.getFile(options.url);
                }
                return await Server.call(options.url, options.params || {
                    pageIndex:1,
                    pageSize:1000,
                    status:1
                }).then(res => {
                    res = res.records || res;
                    return res.map(x=>{
                        if(typeof(x)=="string"){
                            return {value:x, label:x};
                        }
                        return {value:x["ID"] || x["value"], label:x["Name"] || x["label"]};
                    });
                })
            } else if (typeof (options) == "function") {
                let p = options.apply();
                if (p instanceof Promise) {
                    return Promise.resolve(p).then(res => this.parseOptions(res, splitTag));
                }
                return this.parseOptions(p, splitTag);
            } else if (typeof (options) == "object" && Array.isArray(options) && options.length > 0 && typeof (options[0]) == "string") {
                return options.map(p => ({ value: p, label: p }));
            }
        }
        return options;
    }

    doFunc(func, me, args) {
        args = args || [];
        try {
            if (typeof func == "function") {
                return func.apply(me, args);
            } else if (typeof func == "string") {
                let mm = func.match(/^(\w+)\((.*)\)$/);
                if (mm && mm.length == 3) {
                    func = mm[1];
                    args = args.concat(mm[2].split(',').map(p => p.replace(/'|"/g, '')));
                }
                let f1 = me[func];
                if (typeof f1 == "function") {
                    return f1.apply(me, args);
                }
            }
            console.log("自定义事件找不到：" + func);
        } catch (e) {
            console.log(e);
            console.log("自定义事件执行错误：" + func);
        }
    }

    getValByKey(obj, key) {
        let keys = key.split(".");
        for (let i = 0; i < keys.length; i++) {
            obj = obj[keys[i]];
            if (obj == null) return null;
        }
        return obj;
    }


    findComponent(me, cmpName) {
        let cmp = cmpName;
        if (typeof (cmp) == "string") {
            while (me) {
                if (me && me.$options && me.$options.components && cmpName in me.$options.components) {
                    cmp = me.$options.components[cmpName];
                    return cmp;
                }

                if (me && me.components && cmpName in me.components) {
                    return me.components[cmpName];
                }
                me = me.$parent || me.parent;
            }
        }
        if (typeof (cmp) == "string") {
            cmp = resolveComponent(cmpName);
        }
        return cmp;
    }

    getDefault(vv) {
        if (!vv) return vv;
        return mydate.getDefaultValue(vv, {});
    }


    //查找检索字段,h5,pc版可以定义不同的检索字段
    getTbSearchFields(tb, serchObj) {
        serchObj = serchObj || {};
        var searchFields = [];
        let searchCfg = ($mbh5 ? (tb.search_h5 || tb.search) : (tb.search_pc || tb.search)) || [];
        if (typeof (searchCfg) == "string") {
            var ss = (searchCfg || "").split(",").filter(p => p != "");
            ss.forEach(p => {
                searchFields.push({ code: p })
            })
        } else if (typeof (searchCfg) == "function") {
            //更复杂的条件，例如：教师可以检索，学生没有检索条件
            searchFields = searchCfg.call(tb);
        } else {
            searchFields = searchCfg;
        }

        searchFields.forEach(p => {
            if (!p.control) {
                var col = tb.columns.filter(p1 => p1.code == p.code)[0];
                if (col) {
                    p.code = col.searchCode || col.code;
                    p.control = col.control;
                    p.label = p.label || col.label;
                    p.default = p.default != undefined ? p.default : col.default;
                    if (col.options) {
                        p.options = col.options;
                    }
                    if (col.select) {
                        p.select = col.select;
                    }

                    p[col.control] = {
                        ...col[col.control], ...p[col.control]
                    };

                    serchObj && (serchObj[p.code] = this.getDefault(p.default));
                } else {
                    p.control = "text";
                    serchObj && (serchObj[p.code] = this.getDefault(p.default) || "");
                }
            } else {
                serchObj && (serchObj[p.code] = this.getDefault(p.default));
            }
        })

        return searchFields;
    }

    attachStyle(key, styleText) {
        styleText && (styleText = styleText.replace("\n", ""));
        key = key || "_global_style_";
        let _style = document.getElementById(key);
        if (!_style) {
            _style = document.createElement("style");
            _style.id = key;
            _style.type = "text/css";
            _style.innerHTML = styleText;
            document.head.appendChild(_style);
        } else {
            _style.innerHTML = styleText;
        }
    }

    shallowEqual(obj1, obj2) {
        if(obj1==obj2)return true;
        if(obj1==null || obj1==undefined || obj2==null || obj2==undefined)return false;

        const tp1 = typeof (obj1);
        const tp2 = typeof (obj2);
        
        if(tp1!=tp2)return false;

        if (tp1 != "object" || tp2 != "object") {
            return String(obj1) == String(obj2);
        }
        const keys1 = Object.keys(obj1).sort();
        const keys2 = Object.keys(obj2).sort();
        if (keys1.length !== keys2.length) {
            return false;
        }

        for (let index = 0; index < keys1.length; index++) {
            const k1 = keys1[index];
            const k2 = keys2[index];
            if (k1 != k2) return false;
            const v1 = obj1[k1];
            const v2 = obj2[k2];
            if (!this.shallowEqual(v1, v2)) return false;
        }

        return true;
    }

    buildRules(columns) {
        let tb = { columns: columns, rules: {} };

        for (let col of tb.columns) {
            if (col.required == true) {
                if (!tb.rules) {
                    tb.rules = {};
                }
                if (!tb.rules[col.code]) {
                    tb.rules[col.code] = [];
                }
                let rules = tb.rules[col.code];
                let rule = rules.find(p => p.required == true);
                if (!rule) {
                    let tp = undefined;
                    switch (col.type.toLowerCase()) {
                        case "string":
                        case "text":
                            tp = "string";
                            break;
                        case "bool":
                        case "boolean":
                            tp = "boolean";
                            break;
                        case "int":
                            tp = "integer"
                            break;
                        case "array":
                            tp = "array";
                            break;
                        case "date":
                        case "datetime":
                        case "time":
                            tp = "date";
                            break;
                        case "object":
                            tp = "object";
                            break;
                        case "number":
                        case "number2":
                        case "number4":
                            tp = "number";
                            break;
                    };
                    rule = { type: tp, required: true, trigger: 'blur', message: `请录入${col.label}` };

                    if (col.type == "string") {
                        rule.validator = (rule, value) => {
                            return value != undefined && value != null && (String(value).length > 0);
                        }
                    }
                    rules.push(rule);
                }
                //如果字段的可编辑属性是动态的， 对应的规则上也需要添加条件
                if (typeof (col.editable) == "string") {
                    rule.vif = col.editable;
                }
                if (typeof (col.required) == "string") {
                    rule.vif = col.required;
                }
                if (col.type == "bool") {
                    rule.type = "boolean";
                }

                if (col.regex) {
                    let rule = rules.find(p => p.type == "regexp");
                    if (!rule) {
                        let msg = col.message || `${col.label}格式不正确`;
                        rule = { pattern: col.regex, message: msg, trigger: "blur" }
                        if (typeof (col.editable) == "string") {
                            rule.vif = col.editable;
                        }
                        if (typeof (col.required) == "string") {
                            rule.vif = col.required;
                        }
                        rules.push(rule)
                    }
                }
            }
        }

        

        return tb.rules;
    }

    async proceFieldsOptions(cols) {
        if (!cols || !Array.isArray(cols)) return;
        for (let col of cols) {
            if (col.options) {
                col.options = await this.parseOptions(col.options, col?.check?.splitTag || ";");
                if (col.type == "boolean") {
                    col.options.forEach(x => x.value = (x.value == "true" || x.value == "1"));
                }
            }
        }
    }

    string2rows(strfull) {
        //  | 分隔多行  
        //  , 分隔col
        //  : 后面指定col宽度
        return strfull.split("|").map(str => {
            let cols = str.split(",").map(p => p.trim()).filter(p => p.length > 0);
            let row = { type: "row", row: { gutter: 10 } };
            row.items = cols.map(p => {
                let ss = p.split(":");
                if (ss.length == 2) {
                    return { type: "col", col: { span: parseInt(ss[1]) }, field: ss[0] };
                } else {
                    return { type: "col", col: { span: 24 }, field: ss[0] };
                }
            });
            return row
        });
    }

    formatFormItemsDefine(tb) {
        let noneForm = false;
        if (!tb.form) {
            tb.form = tb;
            noneForm = true;
        }
        Object.keys(tb).forEach(key => {
            if (key.startsWith("form")) {
                let form = tb[key];
                if (form && form.columns) {
                    form.columns.forEach(x => {
                        if (x.type == "bool") {
                            x.type = "boolean";
                        }
                    });
                    this.proceFieldsOptions(form.columns);
                }

                if ($mbh5) {
                    form.items = form.items_wx || form.items;
                }
                if (form && form.items) {
                    if (typeof (form.items) == "string") {
                        let rows = this.string2rows(form.items);
                        form.items = rows;
                    }
                    if (!Array.isArray(form.items)) {
                        form.items = [form.items];
                    }
                    form.items.forEach(p0 => {
                        this.formatFormItemDefine(p0, form);
                    });
                }
            }
        });

        if (noneForm == true) {
            tb = tb.form;
        }
    }

    formatFormItemDefine(item, pitem) {
        if (item.items && typeof (item.items) == "string") {
            let rows = this.string2rows(item.items);
            
            //row里面再包含row,取出不要嵌套
            if(item.type=="row" && rows.length==1 && rows[0].type=="row"){
                item.items = rows[0].items;
                item.row = {gutter: 10, ...item.row};
            }else{
                item.items = rows;
            }
        }
        if (!item.type) {
            if (item.row && typeof (item.row) == "string") {
                //例如： row:Title:12,Name:12
                let row = this.string2rows(item.row)[0];
                item.type = row.type;
                item.row = row.row;
                item.items = row.items;
            } else if (item.tab && typeof (item.tab) == "string") {
                //tab:{label:"xxx"}, 可简化为 tab:"xxx"
                item.type = "tab";
                item.tab = { label: item.tab };
            } else if (item.tabs && Array.isArray(item.tabs)) {
                let newItem = { type: "tabs", items: item.tabs };
                if (pitem && pitem.items) {
                    let ix = pitem.items.indexOf(item);
                    pitem.items.splice(ix, 1, newItem);

                    item = newItem;
                }
            } else if (!item.items && typeof (item) == "object" && pitem && pitem.items) {
                //把对象形式展开成数组形式
                let ix = pitem.items.indexOf(item);
                if (ix != -1) {
                    pitem.items.splice(ix, 1);
                    let aa = [];
                    Object.keys(item).map(key => {
                        let obj = item[key];
                        let newItem = { type: key, ...obj };
                        if (Array.isArray(obj)) {
                            newItem = { type: key, items: obj };
                        }
                        pitem.items.splice(ix++, 0, newItem);
                        aa.push(newItem);
                    });
                    aa.forEach(p => this.formatFormItemDefine(p, pitem));
                }
            }
        }

        if (item.items && typeof (item.items) == "object" && !Array.isArray(item.items)) {
            //如果只有一个元素， 
            //例如：  {items:[row]} 可简化为 items:row
            item.items = [item.items];
        }
        if (Array.isArray(item.items)) {
            item.items.forEach(p => {
                this.formatFormItemDefine(p, item);
            });
        }
    }
};

const _Utils = new Utils();

export default _Utils;